﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SilkeyERP.UI.Entities.BI
{
    public static class DataSource
    {
        static IDataProvider instance;
        public static IDataProvider GetDataProvider()
        {
            if (instance == null)
                EnsureDataProvider();
            return instance;
        }
        public static void EnsureDataProvider()
        {
            if (instance != null) return;
            //string dbPath = DevExpress.DemoData.Helpers.DataFilesHelper.FindFile(@"sales.mdb", "Data");
            //System.IO.File.SetAttributes(dbPath, System.IO.FileAttributes.Normal);
            var generator = new SalesGenerator();
            using (ProgressTracker.Instance.StartTracking(generator))
            {
                generator.Run();
                instance = new OleDataProvider();
            }
        }
        public static IObservable<int> Progress
        {
            get { return ((IObservable<int>)ProgressTracker.Instance); }
        }
        #region IObservable
        class ProgressTracker : IObservable<int>
        {
            internal static ProgressTracker Instance = new ProgressTracker();
            IList<IObserver<int>> observers;
            ProgressTracker()
            {
                observers = new List<IObserver<int>>();
            }
            public IDisposable StartTracking(IDataGenerator generator)
            {
                return new TrackingContext(generator, this);
            }
            IDisposable IObservable<int>.Subscribe(IObserver<int> observer)
            {
                return new Subscription(this, observer);
            }
            void generator_Start(object sender, ProgressEventArgs e)
            {
                foreach (IObserver<int> observer in observers)
                    observer.OnNext(e.Progress);
            }
            void generator_Complete(object sender, ProgressEventArgs e)
            {
                foreach (IObserver<int> observer in observers)
                    observer.OnCompleted();
            }
            void generator_Progress(object sender, ProgressEventArgs e)
            {
                foreach (IObserver<int> observer in observers)
                    observer.OnNext(e.Progress);
            }
            class TrackingContext : IDisposable
            {
                IDataGenerator generator;
                ProgressTracker tracker;
                public TrackingContext(IDataGenerator generator, ProgressTracker tracker)
                {
                    this.generator = generator;
                    this.tracker = tracker;
                    generator.GenerationStart += OnGenerationStart;
                    generator.GenerationComplete += OnGenerationComplete;
                    generator.GenerationProgress += OnGenerationProgress;
                }
                void IDisposable.Dispose()
                {
                    generator.GenerationStart -= OnGenerationStart;
                    generator.GenerationComplete -= OnGenerationComplete;
                    generator.GenerationProgress -= OnGenerationProgress;
                }
                void OnGenerationStart(object sender, ProgressEventArgs e)
                {
                    tracker.generator_Start(sender, e);
                }
                void OnGenerationComplete(object sender, ProgressEventArgs e)
                {
                    tracker.generator_Complete(sender, e);
                }
                void OnGenerationProgress(object sender, ProgressEventArgs e)
                {
                    tracker.generator_Progress(sender, e);
                }
            }
            class Subscription : IDisposable
            {
                IObserver<int> observer;
                ProgressTracker tracker;
                public Subscription(ProgressTracker tracker, IObserver<int> observer)
                {
                    if (!tracker.observers.Contains(observer))
                        tracker.observers.Add(observer);
                    this.tracker = tracker;
                    this.observer = observer;
                }
                void IDisposable.Dispose()
                {
                    tracker.observers.Remove(observer);
                }
            }
        }
        #endregion IObservable
    }
}
